﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace SYH.IBLL
{
    /// <summary>
    /// 统一的数据访问接口规范
    /// 下列命名中的 Bo 意为 Business object，业务对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IEntityRepository<T> where T : class, IEntityBase, new()
    {

        void Save();
        /// <summary>
        /// 无限制提取所有业务对象
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetBoCollection();

        /// <summary>
        /// 根据传入的条件直接提取全部的对象数据
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        IQueryable<T> GetBoCollection(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 除了提取本身的对象数据集合外，还提取包含根据表达式提取关联的的对象的集合，
        /// </summary>
        /// <param name="includeProperties">需要直接提取关联类集合数据的表达式集合，通过逗号隔开</param>
        /// <returns></returns>
        IQueryable<T> GetBoCollection(params Expression<Func<T, object>>[] includeProperties);

        /// <summary>
        /// 根据传入的过滤条件提取对象集合，包含根据表达式提取关联的的对象的集合
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="includeProperties"></param>
        /// <returns></returns>
        IQueryable<T> GetBoCollection(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);

        /// <summary>
        /// 根据对象的ID提取具体的对象
        /// </summary>
        /// <param name="id">对象ID</param>
        /// <returns></returns>
        T GetBo(Guid id);

        /// <summary>
        /// 根据 Lambda 表达式提取具体的对象，实际上是提取满足表达式限制的集合的第一个对象集合
        /// </summary>
        /// <param name="predicate">布尔条件的 Lambda 表达式</param>
        /// <returns></returns>
        T GetBo(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 按照指定的属性进行分页，提取分页后的对象集合，在本框架中，通常使用 SortCode
        /// </summary>
        /// <typeparam name="TKey">分页所依赖的属性</typeparam>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页对象的数量</param>
        /// <param name="keySelector">指定分页依赖属性的 Lambda 表达式</param>
        /// <returns></returns>
        IList<T> GetBoPaginate<TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> keySelector,out int count);
        IList<T> GetBoPaginateDescend<TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> keySelector, out int count);

        /// <summary>
        /// 按照指定的属性进行分页，提取分页后的对象的集合
        /// </summary>
        /// <typeparam name="TKey">分页所依赖的属性</typeparam>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页对象的数量</param>
        /// <param name="keySelector">指定分页依赖属性的 Lambda 表达式</param>
        /// <param name="predicate">对象集合过滤 Lambda 表达式</param>
        /// <param name="includeProperties">指定的扩展对象属性的表达式集合，通过逗号隔离</param>
        /// <returns></returns>
        IList<T> GetBoPaginate<TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> keySelector, Expression<Func<T, bool>> predicate, out int count, params Expression<Func<T, object>>[] includeProperties);
        IList<T> GetBoPaginateDescend<TKey>(int pageIndex, int pageSize, Expression<Func<T, TKey>> keySelector, Expression<Func<T, bool>> predicate, out int count, params Expression<Func<T, object>>[] includeProperties);

        /// <summary>
        /// 编辑内存中对应的数据集的对象，并直接持久化。
        /// </summary>
        /// <param name="entity"></param>
        void SaveBo(T entity);

        /// <summary>
        /// 批量编辑并持久化处理的操作，下面参数说明以 Persons 为例
        /// </summary>
        /// <param name="predicate">过滤条件，例如：x=>x.Name=="张三"</param>
        /// <param name="newValueExpression">修改值：x2=> new Person {Name="李四"}</param>
        /// 实际例子：_Service.EditAndSaveBy(x => x.Name == "测试数据", x1 => new SystemWorkSection { Description="用于更改的编辑说明" });
        void SaveBo(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> newValueExpression);

        /// <summary>
        /// 根据传入的对象的 ID 删除对应的业务对象
        /// </summary>
        /// <param name="id"></param>
        void DeleteBo(Guid id);

        /// <summary>
        /// 根据传入的对象，删除数据集的对象。
        /// </summary>
        /// <param name="entity"></param>
        void DeleteBo(T entity);

        /// <summary>
        /// 根据条件执行批量删除并持久化的操作
        /// </summary>
        /// <param name="predicate">条件表达式，例如：x=>x.Name=="abc"，满足的数据对象都将被删除</param>
        void DeleteBo(Expression<Func<T, bool>> predicate);

        #region 以下是针对在当前的 Repository 中需要在同一个 EF 的上下文实例中进行处理的关联对象的处理方法完全一致，具体使用与上面的方式一样
        IQueryable<T1> GetBoCollection<T1>() where T1 : class, IEntityBase, new();
        IQueryable<T1> GetBoCollection<T1>(params Expression<Func<T1, object>>[] includeProperties) where T1 : class, IEntityBase, new();
        IQueryable<T1> GetBoCollection<T1>(Expression<Func<T1, bool>> predicate) where T1 : class, IEntityBase, new();

        T1 GetBo<T1>(Guid id) where T1 : class, IEntityBase, new();
        T1 GetBo<T1>(Expression<Func<T1, bool>> predicate) where T1 : class, IEntityBase, new();

        void SaveBo<T1>(T1 entity) where T1 : class, IEntityBase, new();

        void DeleteBo<T1>(T1 entity) where T1 : class, IEntityBase, new();
        void DeleteBo<T1>(Expression<Func<T, bool>> predicate) where T1 : class, IEntityBase, new();

        #endregion


        #region 一些与状态有关的方法
        /// <summary>
        /// 根据对象ID判断在数据库中是不是新的对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        bool IsNewBo(Guid id);

        /// <summary>
        /// 根据对象ID判断在数据库中是不是存在相应的对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        bool HasAny(Guid id);
        #endregion

        #region 一些动态数据处理方法，这部分的操作，一般用于内存中的数据集合，不做持久化
        void AddBo(T entity);
        void AddBo<T1>(T1 entity) where T1 : class, IEntityBase, new();
        void EditBo(T entity);
        void EditBo<T1>(T1 entity) where T1 : class, IEntityBase, new();
        void RemoveBo(T entity);
        void RemoveBo<T1>(T1 entity) where T1 : class, IEntityBase, new();
        #endregion
    }
}
